﻿// 为Shader命名
Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level"
{
    Properties
    {
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        // 高光反射叠加的颜色，默认为白色
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        // 光泽度，控制高光区域的大小
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }

    SubShader
    {
        Pass
        {
            // 为了正确地得到一些Unity的内置光照变量，如_LightColor0
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            // 为了使用Unity内置的一些变量，如:_LightColor0
            #include "Lighting.cginc"

            /* 声明属性变量 */
            // 颜色值的范围在0~1，故使用fixed精度
            fixed4 _Diffuse;
            fixed4 _Specular;
            // 光泽度数值范围较大，使用float精度
            float _Gloss;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                // 顶点着色器输出颜色值到片元着色器
                fixed3 color : COLOR;
            };

            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                // 使用兰伯特漫反射模型
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
                // 使用reflect函数求出入射光线关于表面法线的反射方向，并进行归一化
                // 因为reflect的入射方向要求由光源指向焦点处（worldLightDir是焦点处指向光源），所以需要取反
                fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
                // 通过Unity内置变量_WorldSpaceCameraPos得到世界空间中的相机位置
                // 通过与世界空间中的顶点坐标进行相减，得到世界空间下的视角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);

                // 根据高光反射公式求出高光反射颜色
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
                
                // 环境光+漫反射+高光反射
                o.color = ambient + diffuse + specular;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.color, 1.0);
            }
            ENDCG
        }
    }

    // 使用Unity内置的Specular Shader兜底
    Fallback "Specular"
}
